﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using snat.model;
using QuickGraph;
using snat.proxy.items;
using snat.model.EventFramework;

namespace gui {
    public class NetworkViewModel : IMutableBidirectionalGraph<object, IEdge<object>> {

        private List<Edge> edges;
        private Dictionary<int, BaseNode> nodes;

        public NetworkViewModel(Dictionary<int, BaseNode> _nodes, List<Edge> _edges)
            : base() {
            this.edges = _edges;
            this.nodes = _nodes;
        }

        public event VertexAction<object> VertexRemoved;
        public event VertexAction<object> VertexAdded;
        public void OnVertexAdded(object source, NodeArgs args) {
            var eh = this.VertexAdded;
            if (eh != null)
                    VertexAdded(args.Node); 
            
        }
        private EventHandler<NodeArgs> nodeListener;
        public EventHandler<NodeArgs> NodeListener {
            get {
                if (nodeListener == null) {
                    nodeListener = new EventHandler<NodeArgs>(OnVertexAdded);
                }
                return nodeListener;
            }
        }

        public event EdgeAction<object, IEdge<object>> EdgeRemoved;
        public event EdgeAction<object, IEdge<object>> EdgeAdded;
        public void OnEdgeAdded(object source, EdgeArgs args) {
            var eh = this.EdgeAdded;
            if (eh != null) {
                EdgeAdded(args.Edge);
            }
        }
        private EventHandler<EdgeArgs> edgeListener;
        public EventHandler<EdgeArgs> EdgeListener {
            get {
                if (edgeListener == null) {
                    edgeListener = new EventHandler<EdgeArgs>(OnEdgeAdded);
                }
                return edgeListener;
            }
        }

        public void ClearEdges(object v) {
            throw new NotImplementedException();
        }

        public void ClearInEdges(object v) {
            throw new NotImplementedException();
        }

        public int RemoveInEdgeIf(object v, EdgePredicate<object, IEdge<object>> edgePredicate) {
            throw new NotImplementedException();
        }

        public void ClearOutEdges(object v) {
            throw new NotImplementedException();
        }

        public int RemoveOutEdgeIf(object v, EdgePredicate<object, IEdge<object>> predicate) {
            throw new NotImplementedException();
        }

        public void TrimEdgeExcess() {
            throw new NotImplementedException();
        }

        public void Clear() {
            throw new NotImplementedException();
        }

        public bool AllowParallelEdges {
            get { return false; }
        }

        public bool IsDirected {
            get { return true; }
        }

        public bool ContainsEdge(object source, object target) {
            return edges.Exists(e => e.From.Equals(source as BaseNode) && e.To.Equals(target as BaseNode));
        }

        public bool TryGetEdge(object source, object target, out IEdge<object> edge) {
            edge = edges.Find(e => e.From.Equals(source as BaseNode) && e.To.Equals(target as BaseNode));
            return edge.Equals(null);
        }

        public bool TryGetEdges(object source, object target, out IEnumerable<IEdge<object>> edges) {
            edges = this.edges.FindAll(e => e.From.Equals(source as BaseNode) && e.To.Equals(target as BaseNode));
            return edges.Count() > 0;
        }

        public bool IsOutEdgesEmpty(object v) {
            return (v as BaseNode).OutEdges.Count == 0;
        }

        public int OutDegree(object v) {
           return (v as BaseNode).OutEdgeCount;
        }

        public IEdge<object> OutEdge(object v, int index) {
            return (v as BaseNode).OutEdges[index];
        }

        public IEnumerable<IEdge<object>> OutEdges(object v) {
            return (v as BaseNode).OutEdges.Cast<IEdge<object>>();
        }

        public bool TryGetOutEdges(object v, out IEnumerable<IEdge<object>> edges) {
            edges = (v as BaseNode).OutEdges;
            return edges.Count() > 0;
        }

        public bool ContainsVertex(object vertex) {
            return this.nodes.Values.Cast<object>().Contains(vertex);
        }

        public bool AddVertex(object v) {
            throw new NotImplementedException();
        }

        public int AddVertexRange(IEnumerable<object> vertices) {
            throw new NotImplementedException();
        }

        public bool RemoveVertex(object v) {
            throw new NotImplementedException();
        }

        public int RemoveVertexIf(VertexPredicate<object> pred) {
            throw new NotImplementedException();
        }

        public bool IsVerticesEmpty {
            get { return nodes.Count == 0; }
        }

        public int VertexCount {
            get { return nodes.Count; }
        }

        public IEnumerable<object> Vertices {
            get { return this.nodes.Values.Cast<object>(); }
        }

        public bool AddVerticesAndEdge(IEdge<object> edge) {
            throw new NotImplementedException();
        }

        public int AddVerticesAndEdgeRange(IEnumerable<IEdge<object>> edges) {
            throw new NotImplementedException();
        }

        public bool AddEdge(IEdge<object> edge) {
            throw new NotImplementedException();
        }

        public int AddEdgeRange(IEnumerable<IEdge<object>> edges) {
            throw new NotImplementedException();
        }

        public bool RemoveEdge(IEdge<object> edge) {
            throw new NotImplementedException();
        }

        public int RemoveEdgeIf(EdgePredicate<object, IEdge<object>> predicate) {
            throw new NotImplementedException();
        }

        public bool ContainsEdge(IEdge<object> edge) {
            return edges.Contains(edge);
        }

        public int EdgeCount {
            get { return edges.Count; }
        }

        public IEnumerable<IEdge<object>> Edges {
            get { return this.edges.Cast<IEdge<object>>(); }
        }

        public bool IsEdgesEmpty {
            get { return edges.Count == 0; }
        }

        public int Degree(object v) {
            return (v as BaseNode).EdgeCount;
        }

        public int InDegree(object v) {
            return (v as BaseNode).InEdgeCount;
        }

        public IEdge<object> InEdge(object v, int index) {
            return (v as BaseNode).InEdges[index];
        }

        public IEnumerable<IEdge<object>> InEdges(object v) {
            return (v as BaseNode).InEdges.Cast<IEdge<object>>();
        }

        public bool IsInEdgesEmpty(object v) {
            return (v as BaseNode).InEdgeCount == 0;
        }

        public bool TryGetInEdges(object v, out IEnumerable<IEdge<object>> edges) {
            edges = (v as BaseNode).InEdges;
            return edges.Count() > 0;
        }
    }
}